package com.connector.base.message.impl;

import com.connector.base.connection.Connection;
import com.connector.base.message.MessageHandler;
import com.connector.base.message.PacketReceiver;
import com.connector.base.message.model.BaseMessage;
import com.connector.base.protocol.Command;
import com.connector.base.protocol.Packet;
import com.connector.base.utils.ErrorCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class MessageDispatcher implements PacketReceiver
{
    private static final Logger log;
    private final Map<Byte, MessageHandler> handlers;

    public MessageDispatcher() {
        this.handlers = new HashMap<Byte, MessageHandler>();
    }

    public void register(final Command command, final MessageHandler handler) {
        this.handlers.put(command.cmd, handler);
    }

    public void register(final Command command, final Supplier<MessageHandler> handlerSupplier, final boolean enabled) {
        if (enabled && !this.handlers.containsKey(command.cmd)) {
            this.register(command, handlerSupplier.get());
        }
    }

    public void register(final Command command, final Supplier<MessageHandler> handlerSupplier) {
        this.register(command, handlerSupplier, true);
    }

    public MessageHandler unRegister(final Command command) {
        return this.handlers.remove(command.cmd);
    }

    @Override
    public void onReceive(final Packet packet, final Connection connection) {
        final MessageHandler handler = this.handlers.get(packet.getCmd());
        if (handler != null) {
            try {
                handler.handle(packet, connection);
            }
            catch (Throwable throwable) {
                MessageDispatcher.log.error("dispatch message ex, packet={}, connect={}, body={}", new Object[] { packet, connection, Arrays.toString(packet.getBody()), throwable });
                BaseMessage.buildErrorResponse(connection).setErrorCode(ErrorCode.DISPATCH_ERROR).buildResult("Dispather Error", "分发消息失败！").close();
            }
        }
        else {
            MessageDispatcher.log.error("dispatch message failure, cmd={} unsupported", (Object)packet.getCmd());
        }
    }

    static {
        log = LoggerFactory.getLogger((Class) MessageDispatcher.class);
    }
}
